﻿using System;
using System.Collections.Concurrent;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Threading.Tasks;


namespace EncodeUtil
{
    public class BatchEncoder
    {
        public delegate void AfterReadLine(EventInfo eventInfo);
        public delegate void AfterEncodeLineToFile(EventInfo eventInfo);

        private event AfterReadLine OnAfterReadLine;
        private event AfterEncodeLineToFile OnAfterEncodeLineToFile;

        public class ReadLineTarget
        {
            public int Index { get; private set; }
            public string Text { get; set; }

            public ReadLineTarget(int index, string text)
            {
                Index = index;
                Text = text;
            }
        }

        public class EncodeLineTarget
        {
            public int Index { get; private set; }
            public string Text { get; set; }
            public string FilePath { get; set; }

            public EncodeLineTarget(int index, string text, string filePath)
            {
                Index = index;
                Text = text;
                FilePath = filePath;
            }

        }


        private string _srcFilePath;
        private string _outDir;
        private string _format;

        public BatchEncoder(string srcFilePath, string outDir, string format = "png",
            AfterReadLine afterRead = null, AfterEncodeLineToFile afterEncode = null)
        {
            _srcFilePath = srcFilePath;
            _outDir = outDir;
            _format = format;
            OnAfterReadLine += afterRead;
            OnAfterEncodeLineToFile += afterEncode;
        }

        public string SrcFilePath
        {
            get { return _srcFilePath; }
        }

        public string OutDir
        {
            get { return _outDir; }
        }

        public Task StartEncode()
        {
            BlockingCollection<string> lines = new BlockingCollection<string>();

            Task reader = Task.Factory.StartNew(() =>
            {
                int i = 0;
                foreach (var line in FileHelper.GetFileLine(_srcFilePath, Encoding.Default))
                {
                    string newLine = line;
                    if (OnAfterReadLine != null)
                    {
                        var eventInfo = new EventInfo(EventInfo.EventType.OK, new ReadLineTarget(i, newLine));
                        OnAfterReadLine(eventInfo);
                        newLine = (eventInfo.Target as ReadLineTarget).Text;
                    }
                    lines.Add(newLine);
                    ++i;
                }
                lines.CompleteAdding();
            });

            Task writer = Task.Factory.StartNew(() =>
            {
                if (!Directory.Exists(_outDir))
                {
                    Directory.CreateDirectory(_outDir);
                }

                int i = 0;
                while (!lines.IsCompleted)
                {
                    string line = lines.Take();
                    string fileName = string.Format("{0}_{1}.{2}", "QRCode", i.ToString("d4"), _format);
                    string fullPath = Path.Combine(_outDir, fileName);
                    try
                    {
                        QRcodeHelper.EncodeToFile(line, fullPath);
                        if (OnAfterEncodeLineToFile != null)
                        {
                            OnAfterEncodeLineToFile(new EventInfo(EventInfo.EventType.OK,
                                new EncodeLineTarget(i, line, fullPath)));
                        }
                    }
                    catch (Exception ex)
                    {
                        if (OnAfterEncodeLineToFile != null)
                        {
                            OnAfterEncodeLineToFile(new EventInfo(EventInfo.EventType.ERROR, new EncodeLineTarget(i, ex.Message, fullPath)));
                        }
                    }
                    finally
                    {
                        ++i;
                    }
                }
            });

            return writer;
        }
    }
}
